//
//  MTBeacon4Base.swift
//  MTBLETools
//
//  Created by 方强 on 16/10/27.
//  Copyright © 2016年 MT. All rights reserved.
//

import UIKit
import CoreBluetooth

public class MTBeacon4Base: BLEBase {
    
    public static let SendPowerName = ["A","B","C","D"];
    private static let MAXPRIVATEID = 3;
    
    private var baseCallback = BLEBaseCallback();
    private let requsetOption = BLEBaseAction_ActionOption(timeout: 1000);
    public override init(manager: MTBLEManager) {
        super.init(manager: manager);
        baseCallback.onCharactChanged = onMTSeriCharactChanged;
        baseCallback.onBaseConnect = onMTSeriBaseConnect;
        baseCallback.onDisConnect = onMTSeriBaseDisConnect;
        baseCallback.onManualDisConnect = onMTSeriBaseManualDisConnect;
    }
    
    // 连接
    private var callback:MTBeacon4Base_CallBack!;
    private var pwd:String = "";
    public func connect(mac: String!, pwd:String, callback2: MTBeacon4Base_CallBack, retryTimes: Int) -> ErroCode? {
        MTTools.logout(log: "connect->\(mac)");
        self.callback = callback2;
        self.pwd = pwd;
        connectfail = false;
        return super.connect(mac: mac, callback: baseCallback, retryTimes: retryTimes);
    }
    
    private var workingdevice: MTBLEDevice!;
    public func connect(device: MTBLEDevice!, pwd:String, callback2: MTBeacon4Base_CallBack, retryTime: Int) -> ErroCode? {
        self.callback = callback2;
        self.pwd = pwd;
        self.workingdevice = device;
        connectfail = false;
        return super.connect(device: device, callback: baseCallback, retryTime: retryTime);
    }
    
    // 连接成功回调
    private var connectfail:Bool = false;
    private var connectfail_errocode:ErroCode?;
    private func onMTSeriBaseConnect(ble:BLEBase, erro:ErroCode?){
        MTTools.logout(log: "MTSeriaBase onMTSeriBaseConnect->\(erro?.getMsg())");
        
        if(erro?.getCode() != 0){  // 出错误的情况
            callback.onConnect?(self, erro!);
            return;
        }
        
        discoverServices();
    }
    
    // 获取特定服务
    private static let USER_SERVICE_UUID = "F8F0";
    private static let TXD_CHARACT_UUID = "F8F1";
    private static let RXD_CHARACT_UUID = "F8F2";
    private var txd_charact:CBCharacteristic?;
    private var rxd_charact:CBCharacteristic?;
    
    // 发现服务
    private func discoverServices(){
        
        let action = DiscoverServicesAction(serviceuuids: nil, option: BLEBaseAction_ActionOption(timeout: 4000));
        action.onSuccess = {(action) in
            MTTools.logout(log: "discoverservices onSuccess");
            self.discoverCharacts();
        };
        action.onFail = {(action, errocode) in
            MTTools.logout(log: "discoverservices onFail->\(errocode.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = errocode;
            super.disConnect();
        };
        super.addNewAction(action: action);  // 等待4秒
    }
    
    // 发现特征值
    var user_service:CBService?;  // 判断获取到的service是否是需要的
    private func discoverCharacts(){
        
        let services = super.getAllServices();
        if(services == nil){  // 判断是否获取到service
            connectfail = true;
            connectfail_errocode = ErroCode.ERROMAP["getcharacterro"];
            super.disConnect();
            return;
        }
        
        for service in services! {
            if(service.uuid.uuidString == MTBeacon4Base.USER_SERVICE_UUID){
                user_service = service;
                break;
            }
        }
        if(user_service == nil){
            connectfail = true;
            connectfail_errocode = ErroCode.ERROMAP["getcharacterro"];
            super.disConnect();
            return;
        }
        
        var action = DiscoverCharactsAction(service: user_service!, charactuuids: nil, option: BLEBaseAction_ActionOption(timeout: 2000));  // 添加发现命令特征值，等待2秒
        action.onSuccess = {(action) in
            MTTools.logout(log: "discoverCharacts onSuccess cmd_service");
            
            self.haveCharacts();
        };
        action.onFail = {(action, errocode) in
            MTTools.logout(log: "discoverCharacts cmd_service onFail->\(errocode.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = errocode;
            super.disConnect();
        };
        super.addNewAction(action: action);
    }
    
    // 判断是否有需要的特征值
    private func haveCharacts(){
        for charact in (user_service?.characteristics)! {
            if(charact.uuid.uuidString.uppercased() == MTBeacon4Base.TXD_CHARACT_UUID){
                txd_charact = charact;
            }
            if(charact.uuid.uuidString.uppercased() == MTBeacon4Base.RXD_CHARACT_UUID){
                rxd_charact = charact;
            }
        }
        
        if ((txd_charact == nil) || (rxd_charact == nil)) {
            connectfail = true;
            connectfail_errocode = ErroCode.ERROMAP["getcharacterro"];
            super.disConnect();
            return;
        }
        
        enableNotify();
        
    }
    
    // 开启notify
    private func enableNotify(){
        
        var action = SetNotifyAction(charact: rxd_charact, enable: true, option: BLEBaseAction_ActionOption(timeout: 1000));// 开启notify，等待1秒
        action.onSuccess = {(action) in
            
            self.verifyPwd();
            //            self.MTSericonnect = true;       // 连接成功
            //            self.callback.onConnect?(self, ErroCode.ERROMAP["OK"]!);
        };
        action.onFail = {(action, erro) in
            MTTools.logout(log: "discoverCharacts atrecv_charact onFail->\(erro.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = erro;
            super.disConnect();
        };
        
        super.addNewAction(action: action);
        
        addListCharact(charact: rxd_charact);     // 添加到监听列表
    }
    
    // 验证密码
    private func verifyPwd(){
        if(workingdevice.getSetlev() == 0){  // 不需要密码，已经连接成功
            self.MTSericonnect = true;       // 连接成功
            self.callback.onConnect?(self, ErroCode.ERROMAP["OK"]!);
            return;
        }
        if(workingdevice.getSetlev() == 1){  // 需要密码验证
            
            let verifyPwdAction = WriteCharactWithAckAction(sendCharact: txd_charact, reviceCharact: rxd_charact, datas: MTBeacon4Protocol.verifyPwd(pwd: pwd), option: BLEBaseAction_ActionOption(timeout: 1000));
            
            let mMTBeacon4Protocol = MTBeacon4Protocol();
            let mMTBeacon4ProtocolCallback = MTBeacon4Protocol_CallBack();
            mMTBeacon4ProtocolCallback.onVerifyPwd = {(statues, reason) in
                verifyPwdAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
                if(!statues){
                    self.callback.onConnect?(self, ErroCode.ERROMAP["pwderro"]!);
                    return;
                }
                self.MTSericonnect = true;       // 连接成功
                self.callback.onConnect?(self, ErroCode.ERROMAP["OK"]!);
            };
            mMTBeacon4Protocol.setCallBack(mProtocolCallBack: mMTBeacon4ProtocolCallback);
            
            verifyPwdAction.onReciveDatas = {(action, charact, datas) in
                if(datas == nil){
                    return;
                }
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            
            verifyPwdAction.onFail = {(action, errocode) in
                super.disConnect();
                self.callback.onConnect?(self, ErroCode.ERROMAP["pwdfail"]!);
            };
            
            super.addNewAction(action: verifyPwdAction);
            
            return;
        }
    }
    
    // 读取所有参数
    private var readid = 0;
    private var privatedeviceinf = [MTBeaconInfModel]();
    private var publicdeviceinf = MTBeaconInfModel();
    public func readAllInf(device:MTBLEDevice, pwd:String, readinfscallback:MTBeacon4Base_ReadInfsCallBack) -> ErroCode{
        
        var getprivateAction:WriteCharactWithAckAction!;  // 读取私有参数动作
        var getpublicAction:WriteCharactWithAckAction!;   // 读取公有参数动作
        var getversionAction:WriteCharactWithAckAction!;  // 读取固件版本号动作
        
        privatedeviceinf.removeAll();
        
        let callback = MTBeacon4Base_CallBack();
        
        let mMTBeacon4Protocol = MTBeacon4Protocol();
        
        let mMTBeacon4ProtocolCallback = MTBeacon4Protocol_CallBack();
        mMTBeacon4ProtocolCallback.onGetVersion = {(version, statues, reason) in
            getversionAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            
            if(!statues){
                super.disConnect();
                readinfscallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "readversionfail"));
                return;
            }
            
            self.publicdeviceinf.setVersion(version: version!);
            
            self.readid = 0;
            
            getprivateAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.getPrivateBeaconParams(id: self.readid), option: BLEBaseAction_ActionOption(timeout: 1000));
            getprivateAction.onFail = {(action, errocode) in
                readinfscallback.onFail?(self, errocode);
            };
            getprivateAction.onReciveDatas = {(action, charact, datas) in
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            super.addNewAction(action: getprivateAction);
        };
        mMTBeacon4ProtocolCallback.onGetPublicBeaconParams = {(datas, statues, reason) in
            getpublicAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            
            if(!statues){
                super.disConnect();
                readinfscallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "readpublicparamsfail"));
                return;
            }
            self.publicdeviceinf = datas!;
            
            getversionAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.getVersion(), option: BLEBaseAction_ActionOption(timeout: 1000));
            getversionAction.onFail = {(action, errocode) in
                readinfscallback.onFail?(self, errocode);
            };
            getversionAction.onReciveDatas = {(action, charact, datas) in
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            super.addNewAction(action: getversionAction);
        };
        
        mMTBeacon4ProtocolCallback.onGetPrivateBeaconParams = {(datas, statues, reason) in
            getprivateAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            
            if(!statues){
                super.disConnect();
                readinfscallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "readprivateparamsfail"));
                return;
            }
            self.privatedeviceinf.append(datas!);
            
            self.readid += 1;
            
            if(self.readid >= MTBeacon4Base.MAXPRIVATEID){  // 读取完毕
                super.disConnect();
                readinfscallback.onSuccess?(self, self.publicdeviceinf ,self.privatedeviceinf);
                return;
            }
            
            getprivateAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.getPrivateBeaconParams(id: self.readid), option: BLEBaseAction_ActionOption(timeout: 1000));
            getprivateAction.onFail = {(action, errocode) in
                readinfscallback.onFail?(self, errocode);
            };
            getprivateAction.onReciveDatas = {(action, charact, datas) in
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            super.addNewAction(action: getprivateAction);
        };
        
        mMTBeacon4Protocol.setCallBack(mProtocolCallBack: mMTBeacon4ProtocolCallback);
        
        callback.onConnect = {(ble, errocode) in
            if(errocode.getCode() != 0){
                readinfscallback.onFail?(ble, errocode);
                return;
            }

            getpublicAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.getPublicBeaconParams(), option: BLEBaseAction_ActionOption(timeout: 1000));
            getpublicAction.onFail = {(action, errocode) in
                readinfscallback.onFail?(self, errocode);
            };
            getpublicAction.onReciveDatas = {(action, charact, datas) in
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            
            super.addNewAction(action: getpublicAction);
            
        };
        
        let errocode = self.connect(device: device, pwd: pwd, callback2: callback, retryTime: 2);
        
        
        return ErroCode.ERROMAP["OK"]!;
    }
    
    // 设置私有参数major/minor/uuid
    public func setPrivateParamters(device:MTBLEDevice, pwd:String, deviceinf:MTBeaconInfModel, setprivatecallback:MTBeacon4Base_BaseCallBack) -> ErroCode{
       
        var setprivateAction:WriteCharactWithAckAction!;  // 设置私有参数动作
        
        let callback = MTBeacon4Base_CallBack();
        
        let mMTBeacon4Protocol = MTBeacon4Protocol();
        
        let mMTBeacon4ProtocolCallback = MTBeacon4Protocol_CallBack();
        mMTBeacon4ProtocolCallback.onSetPrivateBeaconParams = {(statues, reason) in
            setprivateAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            
            if(!statues){
                super.disConnect();
                setprivatecallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "设置失败"));
                return;
            }
            super.disConnect();
            setprivatecallback.onSuccess?(self);
        };
        
        mMTBeacon4Protocol.setCallBack(mProtocolCallBack: mMTBeacon4ProtocolCallback);
        
        callback.onConnect = {(ble, errocode) in
            if(errocode.getCode() != 0){
                setprivatecallback.onFail?(ble, errocode);
                return;
            }
            
            setprivateAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.setPrivateBeaconParams(mPrivateBeaconParams: deviceinf), option: BLEBaseAction_ActionOption(timeout: 1000));
            setprivateAction.onReciveDatas = {(action, charact, datas) in
                if(datas == nil){
                    return;
                }
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            setprivateAction.onFail = {(action, errocode) in
                super.disConnect();
                setprivatecallback.onFail?(self, errocode);
            };
            
            super.addNewAction(action: setprivateAction);
            
        };
        
        let errocode = self.connect(device: device, pwd: pwd, callback2: callback, retryTime: 2);
        
        return errocode!;
    }
    
    // 设置公有参数
    public func setPublicParamters(device:MTBLEDevice, pwd:String, deviceinf:MTBeaconInfModel, setpubliccallback:MTBeacon4Base_BaseCallBack) -> ErroCode{
        
        var setpublicAction:WriteCharactWithAckAction!;  // 设置私有参数动作
        var setundevelopAction:WriteCharactWithAckAction!;
        
        let callback = MTBeacon4Base_CallBack();
        
        let mMTBeacon4Protocol = MTBeacon4Protocol();
        
        let mMTBeacon4ProtocolCallback = MTBeacon4Protocol_CallBack();
        mMTBeacon4ProtocolCallback.onSetPublicBeaconParams = {(statues, reason) in
            setpublicAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            
            if(!statues){
                super.disConnect();
                setpubliccallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "设置失败"));
                return;
            }
            
            if(deviceinf.getNewpwd() == nil){
                super.disConnect();
                setpubliccallback.onSuccess?(self);
                return;
            }
            
            if(deviceinf.getNewpwd()!.lengthOfBytes(using: String.Encoding.utf8) == 0){  // 取消密码
                setundevelopAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.setDeverlop(id:0x41, msg:""), option: BLEBaseAction_ActionOption(timeout: 1000));
                
                setundevelopAction.onReciveDatas = {(action, charact, datas) in
                    if(datas == nil){
                        return;
                    }
                    mMTBeacon4Protocol.reviceDatas(datas: datas!);
                };
                
                setundevelopAction.onFail = {(action, errocode) in
                    super.disConnect();
                    setpubliccallback.onFail?(self, errocode);
                };
                super.addNewAction(action: setundevelopAction);
                return;
            }
            
            // 设置密码
            setundevelopAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.setDeverlop(id:0x42, msg:deviceinf.getNewpwd()!), option: BLEBaseAction_ActionOption(timeout: 1000));
            
            setundevelopAction.onReciveDatas = {(action, charact, datas) in
                if(datas == nil){
                    return;
                }
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            
            setundevelopAction.onFail = {(action, errocode) in
                super.disConnect();
                setpubliccallback.onFail?(self, errocode);
            };
            super.addNewAction(action: setundevelopAction);
        };
        
        mMTBeacon4ProtocolCallback.onSetDeverlop = {(statues, reason) in
            setundevelopAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            if(!statues){
                super.disConnect();
                setpubliccallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "设置失败"));
                return;
            }
            super.disConnect();
            setpubliccallback.onSuccess?(self);
            return;
        };
        
        mMTBeacon4Protocol.setCallBack(mProtocolCallBack: mMTBeacon4ProtocolCallback);
        
        callback.onConnect = {(ble, errocode) in
            if(errocode.getCode() != 0){
                setpubliccallback.onFail?(ble, errocode);
                return;
            }
            
            setpublicAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.setPublicBeaconParams(mPublicBeaconParams: deviceinf), option: BLEBaseAction_ActionOption(timeout: 1000));
            setpublicAction.onReciveDatas = {(action, charact, datas) in
                if(datas == nil){
                    return;
                }
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            
            super.addNewAction(action: setpublicAction);
            
        };
        
        let errocode = self.connect(device: device, pwd: pwd, callback2: callback, retryTime: 2);
        
        return errocode!;
    }
    
    // 设置部署
    public func setUndevelop(device:MTBLEDevice, pwd:String, setundevelopcallback:MTBeacon4Base_BaseCallBack) -> ErroCode{
        var setundevelopAction:WriteCharactWithAckAction!;  // 设置私有参数动作
        
        let callback = MTBeacon4Base_CallBack();
        
        let mMTBeacon4Protocol = MTBeacon4Protocol();
        
        let mMTBeacon4ProtocolCallback = MTBeacon4Protocol_CallBack();
        mMTBeacon4ProtocolCallback.onSetDeverlop = {(statues, reason) in
            setundevelopAction.setStatues(statues: BLEBaseAction_ActionStatues.DONE);
            if(!statues){
                super.disConnect();
                setundevelopcallback.onFail?(self, ErroCode(code: ErroCode.CUSTOMCODE, msg: "设置失败"));
                return;
            }
            super.disConnect();
            setundevelopcallback.onSuccess?(self);
        };
        mMTBeacon4Protocol.setCallBack(mProtocolCallBack: mMTBeacon4ProtocolCallback);
        
        callback.onConnect = {(ble, errocode) in
            if(errocode.getCode() != 0){
                setundevelopcallback.onFail?(ble, errocode);
                return;
            }
            
            setundevelopAction = WriteCharactWithAckAction(sendCharact: self.txd_charact, reviceCharact: self.rxd_charact, datas: MTBeacon4Protocol.setDeverlop(id:0x43, msg:""), option: BLEBaseAction_ActionOption(timeout: 1000));
            setundevelopAction.onReciveDatas = {(action, charact, datas) in
                if(datas == nil){
                    return;
                }
                mMTBeacon4Protocol.reviceDatas(datas: datas!);
            };
            
            super.addNewAction(action: setundevelopAction);
            
        };
        
        let errocode = self.connect(device: device, pwd: pwd, callback2: callback, retryTime: 2);
        
        return errocode!;
    }
    
    // 断开回调
    private func onMTSeriBaseDisConnect(ble:BLEBase, erro:ErroCode){
        MTSericonnect = false;
        
        if(connectfail){  // 连接失败的时候，就不要继续回调断开
            connectfail = false;
            callback.onConnect?(self, connectfail_errocode!);
            return;
        }
        
        callback.onDisConnect?(self, erro);
    }
    
    // 主动断开
    private func onMTSeriBaseManualDisConnect(ble:BLEBase, erro:ErroCode){
        
        MTSericonnect = false;
        
        if(connectfail){  // 连接失败的时候，就不要继续回调断开
            connectfail = false;
            callback.onConnect?(self, connectfail_errocode!);
            return;
        }
        
        callback.onManualDisConnect?(self, erro);
    }
    
    // 查看可用连接状态
    private var MTSericonnect = false;
    public func isMTSericonnect() -> Bool{
        return (isConnected() && MTSericonnect);
    }
    
    // 监听到notify
    private func onMTSeriCharactChanged(ble:BLEBase, characteristic:CBCharacteristic, datas:Data?){
        MTTools.logout(log: "onMTSeriCharactChanged");
    }
    
    // 添加写数据操作
    public func addWriteDatasAction(action:WriteCharactAction) -> ErroCode?{
        if(!isMTSericonnect()){
            return ErroCode.ERROMAP["unconnect"];
        }
        return addNewAction(action: action);
    }
    
}

// 回调
public class MTBeacon4Base_CallBack: NSObject {
    public override init() {
        super.init();
    }
    
    public var onConnect:((MTBeacon4Base , ErroCode)->Void)?;
    
    public var reTryConnect:((MTBeacon4Base, Int)->Void)?;
    
    public var onDisConnect:((MTBeacon4Base, ErroCode)->Void)?;
    
    public var onManualDisConnect:((MTBeacon4Base, ErroCode)->Void)?;
    
    public var onDatasRecive:((MTBeacon4Base, CBCharacteristic)->Void)?;
}

// 读取数据回调
public class MTBeacon4Base_ReadInfsCallBack: NSObject{
    public override init() {
        super.init();
    }
    
    public var onSuccess:((MTBeacon4Base, MTBeaconInfModel, [MTBeaconInfModel])->Void)?;
    
    public var onFail:((MTBeacon4Base, ErroCode)->Void)?;
}

// 设置通用参数回调
public class MTBeacon4Base_BaseCallBack: NSObject{
    public override init() {
        super.init();
    }
    
    public var onSuccess:((MTBeacon4Base)->Void)?;
    
    public var onFail:((MTBeacon4Base, ErroCode)->Void)?;
}
